#!/usr/bin/env python

import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.api.labs import taskqueue
from schema import *

import logging

class LeakAdder(webapp.RequestHandler):
  def calculate_rank_from_rank_and_iteration(self, rank, iteration):
    computation = rank.computation
    if iteration < 1: # No rank has been calc'd; all pages are equally popular.
      return 1 / float(computation.node_count)
    else:
      base_rank = 0
      if len(rank.ranks) > 0: # This node has inlinks
        base_rank += rank.ranks[iteration - 1]
      leakage = computation.leaks[iteration - 1] / computation.node_count
      return base_rank + leakage
  
  def calculate_leakage_from_rank(self, rank):
    computation = rank.computation
    iteration = computation.iteration_count
    dampening_factor = computation.dampening_factor
    total_rank = self.calculate_rank_from_rank_and_iteration(rank, iteration)
    return dampening_factor * total_rank
  
  def post(self):
    PAGESIZE = 25
    next = None

    computationid = long(self.request.get("computationid"))
    logging.debug("I'll count ranks for computation %i." % computationid)
    computation = RankComputation.get_by_id(computationid)
    logging.debug("The computation key is %s." % str(computation.key()))

    # The initial value is the additive factor
    total = (1 - computation.dampening_factor)
    if self.request.get("total") != "":
      total = float(total)
    logging.debug("I've found %s leaks so far." % total)

    bookmark = self.request.get("rank_key")
    logging.debug("The rank key is %s." % bookmark)
    
    ranks = DocumentRank.all().order("__key__").filter("dangling =", True)
    computation_ranks = ranks.filter("computationid =", computationid)
    if bookmark:
      logging.debug("This is a continuation.")
      logging.debug("The last batch left off with %s." % bookmark)
      next_ranks = computation_ranks.filter('__key__ >=', db.Key(bookmark))
      batch_of_ranks = next_ranks.fetch(PAGESIZE+1)
    else:
      logging.debug("This is the first batch.")
      batch_of_ranks = computation_ranks.fetch(PAGESIZE+1)

      # Plug Leaks
      body = '<form action="/calculate-residual" method="POST">'
      body += '<input type="hidden" name="computationid" value="'
      body += str(computationid) + '" />'
      body += '<input type="submit" value="Residual" /></form>'
      self.response.out.write("<html><body>%s</body></html>" % body)
    
    logging.debug("This batch has %i ranks." % len(batch_of_ranks))
    
    logging.debug("Now I'll calculate some leaks.")
    
    iteration = computation.iteration_count
    node_count = computation.node_count
    dampening_factor = computation.dampening_factor

    for rank in batch_of_ranks[:-1]:
      total += self.calculate_leakage_from_rank(rank)
    
    if len(batch_of_ranks) == PAGESIZE+1:
      logging.debug("There are enough ranks for another batch.")
      next = batch_of_ranks[-1]
      logging.debug("The next batch starts with rank %s." % str(next.key()))
      task = taskqueue.Task(
        url='/calculate-leakage',
        params={
          'computationid': str(computationid),
          'rank_key': str(next.key()),
          'total': str(total),
        }
      )
      task.add(queue_name='parse')
    else:
      total += self.calculate_leakage_from_rank(batch_of_ranks[-1])
      if len(computation.residuals) < 1:
        logging.debug("Creating the leaks list.")
        computation.leaks = [total]
      else:
        computation.leaks.append(total)
      computation.put()


def main():
  logging.getLogger().setLevel(logging.DEBUG)
  wsgiref.handlers.CGIHandler().run(webapp.WSGIApplication([
    ('/calculate-leakage', LeakAdder),
  ]))


if __name__ == '__main__':
  main()
